﻿# Creates the 'Boilen.tt' template files from the '*.cs' source files.

param(
  [switch]$Compact
)


$ErrorActionPreference = 'Stop'

$command = $MyInvocation.MyCommand
$commandDir = [IO.Path]::GetFullPath( (Split-Path $command.Definition -Parent) )
$scriptName = $command.Name

Write-Host '/ Begin' $scriptName


$boilen = 'Boilen'
$release = 'Debug'
$boilenDir = Get-Item "./$boilen/"
$boilenProj = Get-Item "./$boilen/$boilen.csproj"
$boilenT4Name = "$boilen.tt"
$boilenT4 = (Get-Item './').FullPath + $boilenT4Name


Write-Host '|'
Write-Host '| Loading referenced assemblies from' $boilenProj.Name

# Get assembly references from boilen project.
[xml]$boilenProjXml = Get-Content $boilenProj
$referencedAssemblyNames = $boilenProjXml.Project.ItemGroup | % { $_.Reference } | % { $_.Include } | ? { $_ -and $_ -ne 'System' }

foreach( $name in $referencedAssemblyNames ) {
  Write-Host '|  ' $name
}


Write-Host '|'
Write-Host '| Extracting using declarations and source code'

$usingDeclarations = @{}
[string[]]$content = @"
<# /* $boilenT4Name -- Copyright © 2009 -- http://boilen.codeplex.com/ */ #>

// <auto-generated>
//   !!! WARNING !!!
//   !!!   This code was automatically generated from a T4 template.
//   !!!   Do not edit this file directly. Changes to this file will be lost.
//   !!! WARNING !!!
//   
//      Source Template - <#= System.IO.Path.GetFileName(Host.TemplateFile) #>
// </auto-generated>
"@

$sourceFiles = Get-ChildItem $boilenDir.FullName -filter *.cs -recurse | ? { $_.Name -ne 'AssemblyInfo.cs' }
foreach( $source in $sourceFiles ) {
  $sourceName = $source.FullName.Replace( $boilenDir.FullName, '' )
  Write-Host '|  ' $sourceName
  
  $sourceContent = Get-Content $source.FullName
  $index = 0
  
  # Get all "using _;" declarations before the start of the "namespace _", ignoring boilen namespaces.
  while( -not $sourceContent[$index].StartsWith( 'namespace' ) ) {
    if( $sourceContent[$index] -match '^using (.+);$' ) {
      $namespace = $matches[1]
      $includeNamespace = -not $namespace.StartsWith( $boilen )
      $usingDeclarations[$namespace] = $includeNamespace
      Write-Debug ('{0,5} {1}' -f $includeNamespace, $namespace)
    }
    ++$index
  }
  
  # Get all content between the opening and closing braces.
  $start = $index + 1
  while( -not $sourceContent[$start - 1].Trim( ).Contains( '{' ) ) { ++$start }
  
  $end = $sourceContent.Length - 2
  while( -not $sourceContent[$end + 1].Contains( '}' ) ) { --$end }
  
  $code = $sourceContent[$start..$end]
  Write-Debug ('  [{0,2}, {1,3}] -- {2}' -f $start, $end, ($end - $start))
  if( $Compact ) {
    $code = $code | % { $_.Trim( ) } | ? { [bool]$_ -and -not $_.StartsWith( '//' ) }
    Write-Debug ('  Compacted to {0}' -f $code.Count)
  }
  
  $content += "<#+ // $($source.Name)"
  $content += $code
  $content += '#>'
}


Write-Host '|'
Write-Host '| Creating T4 template file' $boilenT4
Write-Debug $boilenT4

[string[]]$header = '<#@ template language="C#" hostspecific="True" debug="True" #>'
$referencedAssemblyNames | % { $header += '<#@ assembly name="{0}" #>' -f $_ }
$usingDeclarations.Keys | ? { $usingDeclarations[$_] } | sort | % { $header += '<#@ import namespace="{0}" #>' -f $_ }
$header | Write-Debug

$fullContent = $header + $content
Set-Content $boilenT4 $fullContent -Encoding UTF8

Write-Host '|'
Write-Host '\ End' $scriptName
